package com.bestcem.xm.user.dao.impl;

import cn.hutool.core.util.StrUtil;
import com.bestcem.xm.user.constant.CommonConstant;
import com.bestcem.xm.user.dao.UserGroupDao;
import com.bestcem.xm.user.dao.mapper.UserGroupMapper;
import com.bestcem.xm.user.entity.mysql.UserGroup;
import com.bestcem.xm.user.entity.pojo.ListUserGroupParamDO;
import com.bestcem.xm.user.entity.pojo.SearchDO;
import com.bestcem.xm.user.entity.pojo.SearchGroupsDO;
import com.bestcem.xm.user.entity.pojo.UserGroupDO;
import com.bestcem.xm.user.enums.GroupStatusEnum;
import com.bestcem.xm.user.grpc.service.param.OrgStatusPageParam;
import com.bestcem.xm.user.grpc.service.param.PageParam;
import com.bestcem.xm.user.grpc.service.param.SortParam;
import com.bestcem.xm.user.service.dto.group.GroupBaseDTO;
import com.bestcem.xm.user.service.dto.group.GroupNodeDTO;
import com.bestcem.xm.user.util.business.DataBaseUtil;
import com.bestcem.xm.user.util.convert.UserGroupConvert;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import javax.validation.constraints.Min;
import java.util.*;

/**
 * 用户组信息daoImpl
 *
 * @author qiongyu.cui <qiongyu.cui@idiaoyan.com>
 * @version v1.0
 * @date 2021/12/29 10:35
 */
@Repository
public class UserGroupDaoImpl implements UserGroupDao {
    @Resource
    private UserGroupConvert userGroupConvert;
    @Resource
    private UserGroupMapper userGroupMapper;

    @Override
    public UserGroupDO getById(String groupId) {
        UserGroup userGroup = userGroupMapper.selectByPrimaryKey(groupId);
        return userGroupConvert.mysqlToDo(userGroup);
    }

    @Override
    public UserGroupDO findOne(UserGroupDO userGroupDO) {
        UserGroup param = userGroupConvert.doToMysql(userGroupDO);
        List<UserGroup> userGroups = userGroupMapper.selectByRecord(param);
        if (CollectionUtils.isEmpty(userGroups)) {
            return null;
        }
        return userGroupConvert.mysqlToDo(userGroups.get(0));
    }

    @Override
    public Boolean updateStatusById(String groupId, Integer groupStatus) {
        UserGroup userGroup = new UserGroup(groupId, groupStatus);
        DataBaseUtil.setUpdateTime(userGroup);
        int result = userGroupMapper.updateByPrimaryKeySelective(userGroup);
        return result == 1;
    }

    @Override
    public List<UserGroupDO> listByLevelIdAndGroupIds(String levelId, List<String> groupIdList) {
        return userGroupMapper.listByLevelIdAndGroupIds(levelId, groupIdList);
    }

    @Override
    public List<UserGroupDO> listPage(UserGroupDO userGroupDO, List<Integer> statuses,
                                      int pageSize, int currentPage) {
        UserGroup userGroup = userGroupConvert.doToMysql(userGroupDO);
        List<UserGroup> userGroups = userGroupMapper.pageByRecord(userGroup, statuses, pageSize, (currentPage - 1) * pageSize);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public Long count(UserGroupDO userGroupDO, List<Integer> statuses) {
        UserGroup userGroup = userGroupConvert.doToMysql(userGroupDO);
        return userGroupMapper.countByRecord(userGroup, statuses);
    }

    @Override
    public List<UserGroupDO> listByCondition(UserGroupDO userGroupDO) {
        UserGroup userGroup = userGroupConvert.doToMysql(userGroupDO);
        List<UserGroup> userGroups = userGroupMapper.selectByRecord(userGroup);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<UserGroupDO> listByConditionAndSort(UserGroupDO userGroupDO, List<Integer> statusList, ArrayList<SortParam> sortList, PageParam page) {
        UserGroup userGroup = userGroupConvert.doToMysql(userGroupDO);
        return userGroupMapper.getListByOrgId(userGroup, page, statusList);
    }

    @Override
    public int countByConditionAndSort(UserGroupDO userGroupDO, List<Integer> statusList) {
        UserGroup userGroup = userGroupConvert.doToMysql(userGroupDO);
        return userGroupMapper.countByConditionAndSort(userGroup, statusList);
    }

    @Override
    public void updateHaveChildrenFlag(String groupId, int haveChildrenFlag) {
        UserGroup userGroup = new UserGroup();
        userGroup.setGroupId(groupId);
        userGroup.setHaveChildrenFlag(haveChildrenFlag);
        DataBaseUtil.setUpdateTime(userGroup);
        userGroupMapper.updateByPrimaryKeySelective(userGroup);
    }

    @Override
    public List<UserGroupDO> listByGroupIds(List<String> groupIdsList) {
        if (CollectionUtils.isEmpty(groupIdsList)) {
            return Collections.emptyList();
        }
        List<UserGroup> userGroups = userGroupMapper.selectByGroupIds(groupIdsList);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<UserGroupDO> getChildrenListByGroupId(String id) {
        List<UserGroup> groupList = userGroupMapper.getChildrenByGroupId(id);
        return userGroupConvert.mysqlsToDos(groupList);
    }

    @Override
    public List<UserGroupDO> listChildrenByGroupIdAndStatus(String id, List<Integer> statuses) {
        List<UserGroup> groupList = userGroupMapper.listChildrenByGroupIdAndStatus(id, statuses);
        return userGroupConvert.mysqlsToDos(groupList);
    }

    @Override
    public List<UserGroupDO> getGroupsByOrgIdAndGroupIds(String orgId, List<String> groupIdsList) {
        List<UserGroup> userGroups = userGroupMapper.getGroupsByOrgIdAndGroupIds(orgId, groupIdsList);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public void insertBatch(List<UserGroupDO> userGroupDos) {
        List<UserGroup> userGroups = userGroupConvert.dosToMysqls(userGroupDos);
        // 分批插入 避免sql超出长度
        List<List<UserGroup>> userGroupBatch = ListUtils.partition(userGroups, CommonConstant.PARTITION_SIZE);
        for (List<UserGroup> userGroupList : userGroupBatch) {
            userGroupMapper.insertBatch(userGroupList);
        }
    }

    @Override
    public void hiddenGroupInsertBatch(List<UserGroupDO> userGroupDos) {
        List<UserGroup> userGroups = userGroupConvert.dosToMysqls(userGroupDos);
        if (CollectionUtils.isNotEmpty(userGroupDos)) {
            for (UserGroup userGroup : userGroups) {
                DataBaseUtil.setCreateAndUpdateTime(userGroup);
            }
            userGroupMapper.insertBatch(userGroups);
        }
    }

    @Override
    public List<UserGroupDO> getByOrgIdAndGroupCodes(String orgId, Set<String> groupCodes) {
        List<UserGroup> userGroups = userGroupMapper.getByOrgIdAndGroupCodes(orgId, groupCodes);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<UserGroupDO> listGroupByUserId(String userId) {
        List<UserGroup> groups = userGroupMapper.listGroupByUserId(userId);
        List<UserGroupDO> userGroupDOS = userGroupConvert.mysqlsToDos(groups);
        if (userGroupDOS == null) {
            return Collections.emptyList();
        }
        return userGroupDOS;
    }

    @Override
    public List<UserGroupDO> listGroupByUserIdAndOrder(String userId) {
        List<UserGroup> groups = userGroupMapper.listGroupByUserIdAndOrder(userId);
        List<UserGroupDO> userGroupDOS = userGroupConvert.mysqlsToDos(groups);
        if (userGroupDOS == null) {
            return Collections.emptyList();
        }
        return userGroupDOS;
    }

    @Override
    public List<UserGroupDO> listGroupByUserIdAndStatus(String userId, Integer status) {
        List<UserGroup> groups = userGroupMapper.listByUserIdAndStatus(userId, status);
        List<UserGroupDO> userGroupDOS = userGroupConvert.mysqlsToDos(groups);
        if (userGroupDOS == null) {
            return Collections.emptyList();
        }
        return userGroupDOS;
    }

    @Override
    public Boolean invalidUserGroup(String groupId, Integer version, String userId, Integer srcStatus, Integer dstStatus) {
        Date operateTime = DataBaseUtil.getDate();
        int result = userGroupMapper.invalidUserGroup(groupId, version, userId, operateTime, srcStatus, dstStatus);
        return result == 1;
    }

    @Override
    public UserGroupDO getRootGroupByOrgId(String orgId) {
        UserGroup userGroup = userGroupMapper.getRootGroupByOrgId(orgId);
        return userGroupConvert.mysqlToDo(userGroup);
    }


    @Override
    public List<UserGroupDO> listUserGroup(ListUserGroupParamDO paramDO) {
        return userGroupConvert.mysqlsToDos(userGroupMapper.listUserGroup(paramDO));
    }

    @Override
    public Long listUserGroupCount(ListUserGroupParamDO paramDO) {
        return userGroupMapper.listUserGroupCount(paramDO);
    }

    @Override
    public List<String> getSubGroupIds(String orgId, String groupIds) {
        return userGroupMapper.getAllSubGroupByGroupId(orgId, groupIds);
    }

    @Override
    public List<GroupBaseDTO> getSubGroupByPage(List<String> subGroupList, Integer start, Integer size) {
        return userGroupMapper.getSubGroupByPage(subGroupList, start, size);
    }

    @Override
    public Long getSubGroupCount(List<String> subGroupList) {
        return Long.valueOf(userGroupMapper.getSubGroupBaseCount(subGroupList));
    }

    @Override
    public List<UserGroupDO> getChildrenListByRootGroupId(String rootGroupId, boolean includeInactive) {
        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(GroupStatusEnum.GROUP_STATUS_ACTIVATED.getIndex());
        statusList.add(GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex());
        if (includeInactive) {
            statusList.add(GroupStatusEnum.GROUP_STATUS_INACTIVATED.getIndex());
        }
        return userGroupMapper.getChildrenListByRootGroupId(rootGroupId, statusList);
    }

    @Override
    public Integer getSelfAndChildrenCountByGroupId(String groupId, boolean includeInactive) {
        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(GroupStatusEnum.GROUP_STATUS_ACTIVATED.getIndex());
        statusList.add(GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex());
        if (includeInactive) {
            statusList.add(GroupStatusEnum.GROUP_STATUS_INACTIVATED.getIndex());
        }
        Integer childrenCountByGroupId = userGroupMapper.getSelfAndChildrenCountByGroupId(groupId, statusList);
        UserGroup userGroup = userGroupMapper.selectByPrimaryKey(groupId);
        return Objects.isNull(userGroup) ? childrenCountByGroupId : childrenCountByGroupId + 1;
    }

    @Override
    public List<UserGroupDO> getListByOrgId(OrgStatusPageParam param) {
        UserGroup userGroup = new UserGroup();
        userGroup.setOrgId(param.getOrgId());
        return userGroupMapper.getListByOrgId(userGroup, param.getPageParam(),
                param.getStatusList());
    }

    @Override
    public Integer userGroupCountByOrgId(OrgStatusPageParam param) {
        UserGroup userGroup = new UserGroup();
        userGroup.setOrgId(param.getOrgId());
        return userGroupMapper.userGroupCountByOrgId(userGroup, param.getStatusList());
    }

    @Override
    public List<UserGroupDO> getListByParentGroupId(OrgStatusPageParam param) {
        return userGroupMapper.getListByParentGroupId(param.getParentGroupId(), param.getPageParam(),
                param.getStatusList());
    }

    @Override
    public int userGroupCountByParentGroupId(OrgStatusPageParam param) {
        return userGroupMapper.userGroupCountByParentGroupId(param.getParentGroupId(), param.getStatusList());
    }

    @Override
    public long countSubRelate(String groupLevelId, List<String> groupIdsList) {
        return userGroupMapper.countSubRelate(groupLevelId, groupIdsList);
    }

    @Override
    public List<UserGroupDO> listPageSubRelate(String groupLevelId, List<String> groupIdsList, @Min(1) int pageSize, @Min(1) int currentPage) {
        List<UserGroup> userGroups = userGroupMapper.listPageSubRelate(groupLevelId, groupIdsList, pageSize, (currentPage - 1) * pageSize);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public long countChild(String parentGroupId, String orgId, List<Integer> statuses, Set<String> parentIds, Set<String> currentIds) {
        return userGroupMapper.countChild(parentGroupId, orgId, statuses, parentIds, currentIds);
    }

    @Override
    public List<UserGroupDO> listChild(String parentGroupId, String orgId, List<Integer> statuses, Set<String> parentIds, Set<String> currentIds, Integer size, Integer page) {
        List<UserGroup> userGroups = userGroupMapper.listChild(parentGroupId, orgId, statuses, parentIds, currentIds
                , size, (page - 1) * size);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public String insertSelective(UserGroupDO userGroup) {
        if (StrUtil.isEmpty(userGroup.getGroupId())) {
            userGroup.setGroupId(DataBaseUtil.generateId());
        }
        DataBaseUtil.setCreateAndUpdateTime(userGroup);
        userGroupMapper.insertSelective(userGroupConvert.doToMysql(userGroup));
        return userGroup.getGroupId();
    }

    @Override
    public int updateByIdAndVersion(Integer versionId, UserGroupDO dtoToDo) {
        UserGroup userGroup = userGroupConvert.doToMysql(dtoToDo);
        DataBaseUtil.setUpdateTime(userGroup);
        return userGroupMapper.updateByIdAndVersion(versionId, userGroup);
    }

    @Override
    public int updateByIdAndVersionWithNull(Integer versionId, UserGroupDO dtoToDo) {
        UserGroup userGroup = userGroupConvert.doToMysql(dtoToDo);
        DataBaseUtil.setUpdateTime(userGroup);
        return userGroupMapper.updateByIdAndVersionWithNull(versionId, userGroup);
    }

    @Override
    public int updateByIdAndVersionWithParentIds(Integer versionId, UserGroupDO dtoToDo) {
        UserGroup userGroup = userGroupConvert.doToMysql(dtoToDo);
        DataBaseUtil.setUpdateTime(userGroup);
        return userGroupMapper.updateByIdAndVersionWithParentIds(versionId, userGroup);
    }

    @Override
    public int batchUpdateById(List<UserGroupDO> dtoToDo) {
        List<UserGroup> groupList = userGroupConvert.dosToMysqls(dtoToDo);
        return userGroupMapper.batchUpdateById(groupList);
    }

    @Override
    public List<String> listByLevelIds(List<String> ids) {
        return userGroupMapper.listGroupByLevelIds(ids);
    }

    @Override
    public int setAdminId(UserGroupDO userGroupDO) {
        UserGroup group = userGroupConvert.doToMysql(userGroupDO);
        DataBaseUtil.setUpdateTime(group);
        return userGroupMapper.setAdminId(group);
    }

    @Override
    public long getByNameAndLevelId(String groupName, String groupParentId, String groupLevelId,
                                    String orgId, ArrayList<Integer> statusList) {
        return userGroupMapper.getByNameAndLevelId(groupName, groupParentId, groupLevelId, orgId, statusList);
    }

    @Override
    public List<UserGroupDO> getByGroupIds(List<String> groupIds) {
        List<UserGroupDO> resultList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(groupIds)) {
            List<UserGroup> userGroups = userGroupMapper.selectByIds(groupIds);
            resultList = userGroupConvert.mysqlsToDos(userGroups);
        }
        return resultList;
    }

    @Override
    public long countSearch(SearchDO searchDO, List<String> parentLevelIds, Set<String> parentIds, Set<String> currentIds) {
        return userGroupMapper.countBySearch(searchDO, parentLevelIds, parentIds, currentIds);
    }

    @Override
    public List<UserGroupDO> listPages(SearchDO searchDO, List<String> levelIds, Set<String> parentIds, Set<String> currentIds, Integer offset, Integer size) {
        List<UserGroup> userGroups = userGroupMapper.groupPage(searchDO, levelIds, parentIds, currentIds, offset, size);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<UserGroupDO> listByOrgIdOrPage(String orgId, Integer offset, Integer size, boolean isPage) {
        return userGroupMapper.listByOrgIdOrPage(orgId, offset, size, isPage);
    }

    @Override
    public Integer getOtherChildrenCount(String groupId, List<Integer> statuses) {
        return userGroupMapper.getOtherChildrenCount(groupId, statuses);
    }

    @Override
    public Integer deleteChildrenSeatLocationPids(String groupId, Integer status, int seat) {
        return userGroupMapper.deleteChildrenSeatLocationPids(groupId, status, seat);
    }

    @Override
    public Integer refreshAllChildrenParentId(String orgId, String parentId, String lastNotHiddenGroup) {
        return userGroupMapper.refreshAllChildrenParentId(orgId, parentId, lastNotHiddenGroup);
    }

    @Override
    public List<UserGroupDO> listByGroupIdsByUserId(List<String> data, Boolean includeChildFlag, Boolean filterStatusFlag, PageParam pageParam) {
        Integer page = (pageParam.getPage() - 1) * pageParam.getSize();
        Integer size = pageParam.getSize();
        return userGroupMapper.listByGroupIdsByUserId(data, includeChildFlag, filterStatusFlag, page, size);
    }

    @Override
    public Long listByGroupIdsByUserIdCount(List<String> data, Boolean includeChildFlag, Boolean filterStatusFlag) {
        return userGroupMapper.listByGroupIdsByUserIdCount(data, includeChildFlag, filterStatusFlag);
    }

    @Override
    public long countChildrenNum(String groupId, String groupLevelId, List<Integer> statusList) {
        return userGroupMapper.countChildrenNum(groupId, groupLevelId, statusList);
    }

    @Override
    public List<UserGroupDO> listPageChildren(String groupId, String groupLevelId, List<Integer> statusList,
                                              int pageSize, int currentPage) {
        List<UserGroup> userGroups = userGroupMapper.listPageChildren(groupId, groupLevelId, statusList, pageSize, (currentPage - 1) * pageSize);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<GroupBaseDTO> listRelateGroups(List<String> relatedIds, Integer page, Integer size) {
        return userGroupMapper.listRelateGroups(relatedIds, page, size);
    }

    @Override
    public Integer listRelateGroupsCount(List<String> relatedIds) {
        return userGroupMapper.listRelateGroupsCount(relatedIds);
    }


    @Override
    public List<GroupNodeDTO> getChildrenGroup(String parentId, boolean includeInactive) {
        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(GroupStatusEnum.GROUP_STATUS_ACTIVATED.getIndex());
        statusList.add(GroupStatusEnum.GROUP_STATUS_HIDDEN.getIndex());
        if (includeInactive) {
            statusList.add(GroupStatusEnum.GROUP_STATUS_INACTIVATED.getIndex());
        }
        return userGroupMapper.getChildrenGroup(parentId, statusList);
    }


    @Override
    public List<UserGroupDO> getGroupsByUserIdLeftJoinGroup(String userId) {
        return userGroupMapper.getGroupsByUserIdLeftJoinGroup(userId);
    }

    @Override
    public List<UserGroupDO> listByGroupIdsAndStatus(List<String> groupIds, Integer status) {
        List<UserGroup> userGroups = userGroupMapper.listByGroupIdsAndStatus(groupIds, status);
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<UserGroupDO> listGroupsByCodes(String orgId, List<String> groupCodesList, List<Integer> statusList) {
        return userGroupMapper.listGroupsByCodes(orgId, groupCodesList, statusList);
    }

    @Override
    public Long getSelfAndChildrenUserNum(Integer userStatus, String groupId, String groupLevelId, String userId, Integer... statuses) {
        return userGroupMapper.getSelfAndChildrenUserNum(userStatus, groupId, groupLevelId, userId, statuses);
    }

    @Override
    public List<String> getChildrenIdsByStatus(String groupId, Integer status) {
        return userGroupMapper.getChildrenIdsByStatus(groupId, status);
    }

    @Override
    public void updateChildrenStatus(List<String> validGroupIds, String userId, Integer destStatus) {
        userGroupMapper.updateChildrenStatus(validGroupIds, userId, destStatus, DataBaseUtil.getDate());
    }

    @Override
    public List<UserGroupDO> listChildrenByParentIds(List<String> groupParentIds) {
        List<UserGroup> userGroups = userGroupMapper.listChildrenByParentIds(groupParentIds);
        if (CollectionUtils.isEmpty(userGroups)) {
            return new ArrayList<>();
        }
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<UserGroupDO> listByGroupIdsAndLevelId(List<String> groupIds, String levelId) {
        List<UserGroup> userGroups = userGroupMapper.listByGroupIdsAndLevelId(groupIds, levelId);
        if (CollectionUtils.isEmpty(userGroups)) {
            return new ArrayList<>();
        }
        return userGroupConvert.mysqlsToDos(userGroups);
    }

    @Override
    public List<UserGroupDO> searchGroups(SearchGroupsDO searchGroupsDO) {
        return userGroupMapper.searchGroups(searchGroupsDO);
    }

    @Override
    public Long searchGroupsCount(SearchGroupsDO searchGroupsDO) {
        return userGroupMapper.searchGroupsCount(searchGroupsDO);
    }

    @Override
    public List<UserGroupDO> getSeqAndOrgId(Integer offset, Integer size) {
        List<UserGroup> seqAndOrgId = userGroupMapper.getSeqAndOrgId(offset, size);
        return userGroupConvert.mysqlsToDos(seqAndOrgId);
    }

    @Override
    public int updateHiddenGroupName(String orgId, String groupId, String groupName) {
        return userGroupMapper.updateHiddenGroupName(orgId, groupId, groupName);
    }

    @Override
    public List<UserGroupDO> getGroupByLevelIdAndStatusList(String levelId, List<Integer> statusList) {
        List<UserGroup> groupList = userGroupMapper.getGroupByLevelIdAndStatusList(levelId, statusList);
        return userGroupConvert.mysqlsToDos(groupList);
    }


    @Override
    public List<UserGroupDO> getAllSubGroup(String orgId, String groupId) {
        List<UserGroup> groupList = userGroupMapper.getAllSubGroup(orgId, groupId);
        return userGroupConvert.mysqlsToDos(groupList);
    }

    @Override
    public List<UserGroupDO> listSubGroupByGroupId(String orgId, String groupId) {
        List<UserGroup> groupList = userGroupMapper.listSubGroupByGroupId(orgId, groupId);
        return userGroupConvert.mysqlsToDos(groupList);
    }

    @Override
    public List<UserGroupDO> listByOrgIdAndStatuses(String orgId, Integer... statuses) {
        List<UserGroup> groupList = userGroupMapper.listByOrgIdAndStatuses(orgId, statuses);
        return userGroupConvert.mysqlsToDos(groupList);
    }

    @Override
    public Integer deleteInvalidGroup(List<String> groupIdList) {
        return userGroupMapper.deleteInvalidGroup(groupIdList);
    }

    @Override
    public List<String> listChildrenByParentId(String orgId, String groupId, int page, int size) {
        int start = (page - 1) * size;
        return userGroupMapper.listChildrenByParentId(orgId, groupId, start, size);
    }

    @Override
    public Long countChildrenByParentId(String orgId, String groupId) {
        return userGroupMapper.countChildrenByParentId(orgId, groupId);
    }

    @Override
    public void deleteRelationsOfUser(String userId) {
        userGroupMapper.deleteRelationsOfUser(userId);
    }
}
